#import "Body.h"

@implementation Body

- init
{
	[super init];

	bodyDelta = maskDelta = 1;  //must not be < 1
	maskDist = bodyDist = 1;
	currentBodyListIndex = 0;
	bodyFrameIndexCounter = maskFrameIndexCounter = 0;
	bodyFrameRect.origin.x = 0.0;
	bodyFrameRect.origin.y = 0.0;
	maskFrameRect.origin.x = 0.0;
	maskFrameRect.origin.y = 0.0;
	firstState = YES;

	return self;
}

- (BOOL)doUntilDone
{
BOOL maskDone;
	maskDone = NO;
    if(firstState){
		currentImage = [self setBodyImage];
    	[self setFrameRectForBody]; //set frame size
		[self setFrameRectForMask];		
		[self setStartPosition:centerOfScreen];  //first body and mask position

		firstState = NO;

        [self drawBody];
		[self setImageListIndex];
		currentImage = [self setBodyImage];
		[self setFrameRectForBody]; //set frame size
		bodyPosition = [self adjustPositionForBody: bodyPosition];
    }
    else {
		
    	maskDone = [self eraseBody];
		[self setFrameRectForMask];		
	    maskPosition = [self adjustPositionForMask: maskPosition];
		//draw body
        [self drawBody];
		[self setImageListIndex];
		currentImage = [self setBodyImage];
		[self setFrameRectForBody]; //set frame size
		bodyPosition = [self adjustPositionForBody: bodyPosition];
	}

    if(maskDone){
        return YES; //this body done
	}	
    else{
        return NO;
	}
}
- setImageListIndex
{
	currentBodyListIndex =  floor((bodyFrameIndexCounter * frameDelta) *
	(bodyFrameIndexCounter * frameDelta) *
	(bodyFrameIndexCounter * frameDelta) *
	(bodyFrameIndexCounter * frameDelta));
	bodyFrameIndexCounter++;
	if(currentBodyListIndex >= numberOfFrames - 1)
		currentBodyListIndex = numberOfFrames - 1;
 	return self;
}	


//		4
//uses X to make expotential curve for calculating movement of object
//idea was to start slow and speed up expotentially
//the smaller the value of objectSpeed the faster the object moves
//I.E. if the number is 2 then it take 2 steps to move the whole distance	
- setObjectSpeed:(float)objectSpeed
{
float radius,x,y;


	x = bounds.size.width;
	y = bounds.size.height;
	radius = (sqrt(x*x + y*y))/2;  // of screen bounds

	distDelta = (sqrt(sqrt(radius)))/(1 + objectSpeed);

	frameDelta = (sqrt(sqrt(numberOfFrames)))/(1 + objectSpeed);

	return self;
}			

- free
{
	return [super free];
}

- (NXImage *)setBodyImage
{
	return ([imageList objectAt:currentBodyListIndex]);	

}

- setImageList:(List *)list
{

	imageList = list;
		return self;
}

- setMaskList:(List *)list
{
	maskList = list;
	return self;
}

- setNumberOfFrames
{
	numberOfFrames = [imageList count];
    return self;
}
- setStartPosition:(NXPoint)point  //where body starts out
{
    bodyPosition.x = point.x - floor((bodyFrameRect.size.width / 2));
	bodyPosition.y = point.y - floor((bodyFrameRect.size.height / 2));
    maskPosition.x = point.x - floor((maskFrameRect.size.width / 2));
	maskPosition.y = point.y - floor((maskFrameRect.size.height / 2));
    return self;
}


- setStarsOutlet: (id)starsOutlet
{
	starsObject = starsOutlet;
	return self;
}

- setFrameRectForBody
{
NXSize size;
	[currentImage getSize: &size];
	
	//adjust the rectangle to reflect actual image that was built
	// so that you know when it actually crosses the viewscreen
		
	bodyFrameRect.origin.x = 8.0;
	bodyFrameRect.origin.y = 8.0;
	bodyFrameRect.size.width = size.width-16;
	bodyFrameRect.size.height = size.height-16;
    return self;
}

- setFrameRectForMask
{
	maskFrameRect.size.width = bodyFrameRect.size.width;
	maskFrameRect.size.height = bodyFrameRect.size.height;
	return self;
}

//bodyFrameRect is actual size of real image inside a black image
// 8 pixels bigger on all sides
//bodyPosition is where the actual image will be composited

- drawBody
{

NXPoint offset;
NXRect adjustedRect={0.0,0.0,bodyFrameRect.size.width+16,
bodyFrameRect.size.height+16};

    if (bodyPosition.x  < (bounds.size.width + bodyFrameRect.size.width) &&
    	bodyPosition.x > (bounds.origin.x - (bodyFrameRect.size.width + 1)) &&
    	bodyPosition.y  < (bounds.size.height + bodyFrameRect.size.width) &&
    	bodyPosition.y > (bounds.origin.y-(bodyFrameRect.size.height + 1))){


	[self setVoidRect:bodyIndex];
		
	offset.x = bodyPosition.x - 8;
	offset.y = bodyPosition.y - 8;

    [currentImage composite:NX_COPY fromRect:&adjustedRect
	 toPoint:&offset];
	}

	return self;
}

- (BOOL)eraseBody
{
NXRect maskRect;

    if (maskPosition.x  < (bounds.size.width  + maskFrameRect.size.width) &&
    maskPosition.x > (bounds.origin.x-(maskFrameRect.size.width + 1)) &&
    maskPosition.y  < (bounds.size.height + maskFrameRect.size.width) &&
    maskPosition.y > (bounds.origin.y -(maskFrameRect.size.height + 1))){
	
		maskRect.origin.x = maskPosition.x;
		maskRect.origin.y = maskPosition.y;
		maskRect.size.width = maskFrameRect.size.width;
		maskRect.size.height = maskFrameRect.size.height;

		PSsetgray(0);
		NXRectFill(&maskRect);
		return NO;
	}
	else{
        return YES;
	}
}
//figure out new x,y position for moving object
- (NXPoint)adjustPositionForBody:(NXPoint)position 
{
	bodyDist = floor((distDelta * bodyDelta) * (distDelta * bodyDelta) * (distDelta * bodyDelta) * (distDelta * bodyDelta));
	bodyDelta++;	
	position.x = floor((centerOfScreen.x - (bodyFrameRect.size.width / 2))
	 + (bodyDist * cos(theta)));
	position.y = floor((centerOfScreen.y - (bodyFrameRect.size.height / 2))
	 + (bodyDist * sin(theta)));
	return position;
}

- (NXPoint)adjustPositionForMask:(NXPoint)position 
{
	    maskDist = floor((distDelta * maskDelta) * (distDelta * maskDelta) * (distDelta * maskDelta) * (distDelta * maskDelta));
	maskDelta++;

	position.x = floor((centerOfScreen.x - (maskFrameRect.size.width / 2))
	 + (maskDist * cos(theta)));
	position.y = floor((centerOfScreen.y - (maskFrameRect.size.height / 2))
	 + (maskDist * sin(theta)));
	return position;
}


//assumes position and size rects have been set for mask and body
- setVoidRect:(int)index
{
AvoidStruct avoidStruct;
const NXRect bodyRect = {bodyPosition.x,bodyPosition.y,
bodyFrameRect.size.width,bodyFrameRect.size.height};

	//actual image is centered in a black rectangle 8 pixels
	//bigger in each direction
	//since bodyPosition and bodyFrameRect are set to the image
	// that is in the oversized rect, adjust avoidance to
	// real origin of black rectangle and make width and height
	// actual image size plus 8 pixels - this makes the assumption
	//stars are drawn from 0,0 to 8 pixels right and up.
	
	avoidStruct.avoid.origin.x = bodyRect.origin.x-8;
	avoidStruct.avoid.origin.y = bodyRect.origin.y-8;
	avoidStruct.avoid.size.width = bodyRect.size.width+8;	
	avoidStruct.avoid.size.height = bodyRect.size.height+8;
	[avoidStorage replaceElementAt:(unsigned int)bodyIndex with:&avoidStruct];
	return self; 
}
- setBoundsRect:(NXRect *)r
{

// screen border width is 5 pixels
// make ship bounds 1 pixel less so that
// when border shrinks by 1 it won't
// affect objects - bounds will catch up

    NXSetRect(&bounds,
    r->origin.x,
    r->origin.y,
    r->size.width,
    r->size.height);
    [self setCenter]; 
	return self;
}
- setCenter
{
    centerOfScreen.x = (bounds.size.width / 2) + bounds.origin.x;
 	centerOfScreen.y = bounds.size.height / 2 + bounds.origin.y;
    return self;
}

- setAngle:(float)angle;
{
	theta = angle;
	return self;

}
- setAvoidStorage:(Storage *)storageObject
{
	avoidStorage = storageObject;
	return self;
}

- setBodyIndex:(int)index
{
	bodyIndex = index;
	return self;
}


@end
